<?php

namespace App\V1\Models\RDBS;

use \App\Libraries\RDBS\QueryBuilder,
    \Phalcon\Di,
    \App\Helpers\Utils;

/**
 * 模板基础类
 * @package App\Models\RDBS
 */
class Model {

    #region 属性

    /**
     * 依赖注册组件
     * @var \Phalcon\Di
     */
    protected $di;

    /**
     * 数据库连接对象
     * @var \App\Libraries\RDBS\QueryBuilder
     */
    protected $db;

    /**
     * 静态数据库连接对象
     * @var \App\Libraries\RDBS\QueryBuilder
     */
    private static $_db;

    #endregion

    #region 构造函数

    /**
     * 构造函数
     */
    public function __construct() {
        $this->di = Di::getDefault();
        $this->initDb();
    }

    /**
     * 初始化db对象
     */
    protected function initDb() {
        if (!isset(self::$_db) || !self::$_db) {
            self::$_db = new QueryBuilder($this->di);
        }
        $this->db = self::$_db;
    }

    #endregion

    #region 事务

    /**
     * 开始事务
     *
     * @param bool $nesting 是否嵌套
     * @return bool
     */
    public function begin($nesting = true) {
        $this->db->begin($nesting);
    }

    /**
     * 回滚事务
     *
     * @param bool $nesting 是否嵌套
     * @return bool
     */
    public function rollback($nesting = true) {
        $this->db->rollback($nesting);
    }

    /**
     * 提交事务
     *
     * @param bool $nesting 是否嵌套
     * @return bool
     */
    public function commit($nesting = true) {
        $this->db->commit($nesting);
    }

    /**
     * 返回错误信息
     * @return array
     */
    public function getErrorInfo() {
        return $this->db->getErrorInfo();
    }

    #endregion

    #region 查询构造器

    #region Select

    /**
     * Select 生成查询的Select部分
     * @param    string | array $select
     * @param    mixed $escape 保护标识符
     * @return   Model
     */
    public function select($select = '*', $escape = NULL) {
        $this->db->select($select, $escape);
        return $this;
    }

    #endregion

    #region Select MAX

    /**
     * Select Max 生成查询的 Select MAX(field)部分
     *
     * @param    string $select 要查询的字段名
     * @param    string $alias 别名
     * @return  Model
     */
    public function max($select = '', $alias = '') {
        $this->db->max($select, $alias);
        return $this;
    }

    #endregion

    #region Select MIN

    /**
     * Select Min 生成查询的 Select MIN(field)部分
     *
     * @param    string $select 要查询的字段名
     * @param    string $alias 别名
     * @return  Model
     */
    public function min($select = '', $alias = '') {
        $this->db->min($select, $alias);
        return $this;
    }

    #endregion

    #region Select Average

    /**
     * Select Average 生成查询的 Select AVG(field)部分
     *
     * @param    string $select 要查询的字段名
     * @param    string $alias 别名
     * @return  Model
     */
    public function avg($select = '', $alias = '') {
        $this->db->avg($select, $alias);
        return $this;
    }

    #endregion

    #region Select SUM

    /**
     * Select Sum 生成查询的 Select SUM(field)部分
     *
     * @param    string $select 要查询的字段名
     * @param    string $alias 别名
     * @return  Model
     */
    public function sum($select = '', $alias = '') {
        $this->db->sum($select, $alias);
        return $this;
    }

    #endregion

    #region DISTINCT

    /**
     * DISTINCT 设置DISTINCT标志，告诉查询字符串编译器添加 DISTINCT
     *
     * @param    bool $val
     * @return  Model
     */
    public function distinct($val = TRUE) {
        $this->db->distinct($val);
        return $this;
    }

    #endregion

    #region From

    /**
     * From 生成查询的FROM部分
     *
     * @param    string | array $from 表名或者表名列表
     * @return  Model
     */
    public function from($from) {
        $this->db->from($from);
        return $this;
    }

    #endregion

    #region JOIN

    /**
     * JOIN 生成查询的JOIN部分
     *
     * @param    string JOIN 表
     * @param    string    连接条件
     * @param    string    连接类型
     * @param    string 是否需要添加保护标识符
     * @return  Model
     */
    public function join($table, $cond, $type = '', $escape = NULL) {
        $this->db->join($table, $cond, $type, $escape);
        return $this;
    }

    #endregion

    #region Where

    /**
     * Where 生成查询条件的Where语句部分，多个时用AND连接
     *
     * Generates the WHERE portion of the query. Separates
     * multiple calls with AND
     *
     * @param    mixed $key 键
     * @param    mixed $value 值
     * @param    bool $escape 是否需要添加保护标识符
     * @return Model
     */
    public function where($key, $value = NULL, $escape = TRUE) {
        $this->db->where($key, $value, $escape);
        return $this;
    }

    #endregion

    #region OR Where
    /**
     * OR Where 生成查询条件的Where语句部分，多个时用OR连接
     *
     * @param    mixed $key 键
     * @param    mixed $value 值
     * @param    bool $escape 是否需要添加保护标识符
     * @return Model
     */
    public function orWhere($key, $value = NULL, $escape = TRUE) {
        $this->db->orWhere($key, $value, $escape);
        return $this;
    }

    #endregion

    #region GROUP BY

    /**
     * GROUP BY 生成Group By 部分
     *
     * @param    string $by
     * @param    bool $escape
     * @return  Model
     */
    public function groupBy($by, $escape = NULL) {
        $this->db->groupBy($by, $escape);
        return $this;
    }

    #endregion

    #region HAVING

    /**
     * HAVING 生成查询语句的HAVING，使用AND连接多个条件
     *
     * @param    string $key
     * @param    string $value
     * @param    bool $escape
     * @return  Model
     */
    public function having($key, $value = NULL, $escape = NULL) {
        $this->db->having($key, $value, $escape);
        return $this;
    }

    #endregion

    #region OR HAVING

    /**
     * OR HAVING 生成查询语句的HAVING，使用OR连接多个条件
     *
     * @param    string $key
     * @param    string $value
     * @param    bool $escape
     * @return  Model
     */
    public function orHaving($key, $value = NULL, $escape = NULL) {
        $this->db->orHaving($key, $value, $escape);
        return $this;
    }

    #endregion

    #region ORDER BY

    /**
     * ORDER BY
     *
     * @param    string $orderBy
     * @param    string $direction ASC, DESC or RANDOM
     * @param    bool $escape
     * @return  Model
     */
    public function orderBy($orderBy, $direction = '', $escape = NULL) {
        $this->db->orderBy($orderBy, $direction, $escape);
        return $this;
    }

    #endregion

    #region LIMIT

    /**
     * LIMIT
     *
     * @param    int $value LIMIT value
     * @param    int $offset OFFSET value
     * @return  Model
     */
    public function limit($value, $offset = 0) {
        $this->db->limit($value, $offset);
        return $this;
    }

    #endregion

    #region 设置 OFFSET 的值

    /**
     * 设置 OFFSET 的值
     *
     * @param    int $offset OFFSET value
     * @return  Model
     */
    public function offset($offset) {
        $this->db->offset($offset);
        return $this;
    }

    #endregion

    #region SET 函数

    /**
     * SET 函数
     *
     * @param    string $key
     * @param    string $value
     * @param    bool $escape 是否保护标识符
     * @return  Model
     */
    public function set($key, $value = '', $escape = NULL) {
        $this->db->set($key, $value, $escape);
        return $this;
    }

    #endregion

    #region 获取SELECT查询语句

    /**
     * 获取SELECT查询语句
     *
     * @param    string $table FROM 表名
     * @param    bool $reset 是否重设
     * @return    string
     */
    public function getCompiledSelect($table = '', $reset = TRUE) {
        return $this->db->getCompiledSelect($table, $reset);
    }

    #endregion

    #region 运行 SELECT 语句

    /**
     * 运行SELECT 语句
     *
     * @param    string    the table
     * @param    string    the limit clause
     * @param    string    the offset clause
     * @return    \Phalcon\Db\ResultInterface
     */
    public function get($table = '', $limit = NULL, $offset = NULL) {
        return $this->db->get($table, $limit, $offset);
    }

    #endregion

    #region 查询所有结果的总数

    /**
     * 查询所有结果的总数
     *
     * @param    string
     * @param    bool    the reset clause
     * @return    int
     */
    public function countAllResults($table = '', $reset = TRUE) {
        return $this->db->countAllResults($table, $reset);
    }

    #endregion

    #region 运行SELECT 语句 ，带WHERE条件

    /**
     * 运行SELECT 语句 ，带WHERE条件
     *
     * @param    string $table
     * @param    string $where
     * @param    int $limit
     * @param    int $offset
     * @return    \Phalcon\Db\ResultInterface
     */
    public function getAsWhere($table = '', $where = NULL, $limit = NULL, $offset = NULL) {
        return $this->db->getAsWhere($table, $where, $limit, $offset);
    }

    #endregion

    #region 批量插入

    /**
     * 批量插入
     *
     * @param    string $table 要插入数据的表
     * @param    array $set 要插入的数据集
     * @param    bool $escape 是否添加保护标识符
     * @return   int | bool 成功插入数据的总数 或者 插入失败返回FALSE
     */
    public function insertBatch($table = '', $set = NULL, $escape = NULL) {
        return $this->db->insertBatch($table, $set, $escape);
    }

    #endregion

    #region 设置批量插入

    /**
     * 采用key/value为集合设置插入
     * The "set_insert_batch" function.  Allows key/value pairs to be set for batch inserts
     *
     * @param    mixed
     * @param    string
     * @param    bool
     * @return  Model
     */
    public function setInsertBatch($key, $value = '', $escape = NULL) {
        $this->db->setInsertBatch($key, $value, $escape);
        return $this;
    }

    #endregion

    #region UPDATE

    /**
     * UPDATE
     *
     * Compiles an update string and runs the query.
     *
     * @param    string $table
     * @param    array $set An associative array of update values
     * @param    mixed $where
     * @param    int $limit
     * @return    object
     */
    public function updateAsSet($table = '', $set = NULL, $where = NULL, $limit = NULL) {
        return $this->db->updateAsSet($table, $set, $where, $limit);
    }


    #endregion

    #region 批量更新

    /**
     * 批量更新
     *
     * @param    string    要批量更新的表名
     * @param    array    更新的数组
     * @param    string    查询条件关键字
     * @return    int | bool 成功插入数据的总数 或者 插入失败返回FALSE
     * @throws \Exception
     */
    public function updateBatch($table = '', $set = NULL, $index = NULL) {
        return $this->db->updateBatch($table, $set, $index);
    }

    #endregion

    #region 批量更新数据

    /**
     * 批量处理更新数据
     *
     * @param    array
     * @param    string
     * @param    bool
     * @return  Model
     * @throws \Exception
     */
    public function setUpdateBatch($key, $index = '', $escape = NULL) {
        $this->setUpdateBatch($key, $index, $escape);
        return $this;
    }

    #endregion

    #region 缓存相关

    #region 启用缓存

    /**
     * 启用缓存
     *
     * Starts QB caching
     *
     * @return  Model
     */
    public function startQueryBuildCache() {
        $this->db->startCache();
        return $this;
    }

    #endregion

    #region 停用缓存

    /**
     * 停用缓存
     *
     * Stops QB caching
     *
     * @return  Model
     */
    public function stopQueryBuildCache() {
        $this->db->stopCache();
        return $this;
    }

    #endregion

    #region 清空缓存

    /**
     * 清空缓存
     *
     * @return  Model
     */
    public function flushQueryBuildCache() {
        $this->db->flushCache();
        return $this;
    }

    #endregion

    #endregion

    #region 重设查询构造器属性的值

    /**
     * 重设查询构造器属性的值
     *
     * @return  Model
     */
    public function resetQuery() {
        $this->db->resetQuery();
        return $this;
    }

    #endregion

    #region 返回查询结果第一行的数据

    /**
     * 返回查询结果第一行的数据 语句
     *
     * @param    string    the table
     * @param    string    the limit clause
     * @param    string    the offset clause
     * @return    \Phalcon\Db\ResultInterface
     */
    public function fetchOne($table = '', $limit = NULL, $offset = NULL) {
        $result = $this->get($table, $limit, $offset);
        return $result ? $result->fetch() : null;
    }

    #endregion

    #region 返回查询结果的所有数据

    /**
     * 返回查询结果的所有数据
     *
     * @param    string    the table
     * @param    string    the limit clause
     * @param    string    the offset clause
     * @return    \Phalcon\Db\ResultInterface
     */
    public function fetchAll($table = '', $limit = NULL, $offset = NULL) {
        $result = $this->get($table, $limit, $offset);
        return $result ? $result->fetchAll() : null;
    }

    #endregion

    #endregion

    #region 生成唯一ID

    /**
     * 生成唯一ID
     * @param string $suffix 后缀
     * @param int $len 长度
     * @param string $split 分割符
     * @return string
     */
    protected function createId($suffix = "", $len = 32, $split = "-") {
        $id = Utils::getRandMd5String($suffix, $len);
        return $split ? substr($id, 0, 8) . $split . substr($id, 8, 4) . $split . substr($id, 12, 4) . $split . substr($id, 16, 4) . $split . substr($id, 20, 12) : $id;
    }

    #endregion
}